<?php

namespace common\observer;

use common\model\EntityModel;
use common\model\StatusModel;
use common\model\TaskModel;
use common\service\StatusService;
use support\SingletonTrait;
use teamones\dbeventObserver\interfaces\SplObserver;
use teamones\dbeventObserver\interfaces\SplSubject;

class TaskCheckPlanTimeIsOverdue implements SplObserver
{
    use SingletonTrait;

    /**
     * @inheritDoc
     */
    function update(SplSubject $subject): void
    {
        $updateData = $subject->getSplUpdateData();
        if (!isset($updateData['plan_end_time'])) {
            return;
        }
        $taskData = $subject->getSubjectData();

        // 当前任务是否逾期
        $currentTaskIsOverdue = ($taskData['end_time'] != 0 && $updateData['plan_end_time'] < $taskData['end_time'])
        || ($taskData['end_time'] == 0 && $updateData['plan_end_time'] < strtotime(date('Y-m-d H:i:s'))) ? 'yes' : 'no';

        $taskData['json'] = json_decode($taskData['json'], true);

        if (empty($taskData['json']['task_is_overdue']) ||
            $currentTaskIsOverdue !== $taskData['json']['task_is_overdue']
        ) {
            model(TaskModel::class)->execute("UPDATE task SET json = JSON_SET(IFNULL(json, '{}'), concat('$.task_is_overdue'), '{$currentTaskIsOverdue}') where id = {$taskData['id']}");
        }

        $designModuleData = module_by_code('design');
        $storyboardModuleData = module_by_code('storyboard');
        $finalStatus = StatusService::getInstance()->getTaskDoneStatus();
        $remakeStatus = StatusService::getInstance()->getTaskDefaultRemakeStatus();

        // 只有工序和工序分类任务才进行下面的环节任务、实体逾期判断
        if (!in_array($taskData['step_type'], [TaskModel::STEP_TYPE_STEP, TaskModel::STEP_TYPE_STEP_CATEGORY])) {
            return;
        }
        $entityData = model(EntityModel::class)->where(['id' => $taskData['entity_id']])->find();
        if (empty($entityData)) {
            return;
        }
        // 找到有关这个实体的所有上/下游
        $entityList = model(EntityModel::class)
            ->field("entity.id, entity.module_id, json_unquote(json_extract(entity.json, concat('$.', m.code, '_is_abnormal'))) as is_abnormal")
            ->join('module m on m.id = entity.module_id')
            ->where([
                'entity.code' => $entityData['code'],
                'entity.project_id' => $entityData['project_id'],
                'entity.initial_episode_code' => $entityData['initial_episode_code'],
                'entity.showings_number' => $entityData['showings_number']
            ])
            ->select();
        // 找到上游
        $upStreamEntityData = [];
        foreach ($entityList as $entityItem) {
            if ($entityItem['module_id'] == $designModuleData['id'] || $entityItem['module_id'] == $storyboardModuleData['id']) {
                $upStreamEntityData = $entityItem;
            }
        }
        if (empty($upStreamEntityData)) {
            return;
        }
        $entityIds = array_column($entityList, 'id');
        $taskList = model(TaskModel::class)->where(['entity_id' => ['IN', $entityIds]])->select();
        $upEntityStepCategoryTaskList = [];
        // 获取该实体有多少个工序类型
        foreach ($taskList as $taskItem) {
            if ($taskItem['step_type'] == 'step_category') {
                $taskStepCategoryFilter[0][]['step_category_id'] = $taskItem['step_category_id'];
                $upEntityStepCategoryTaskList[] = [
                    'id' => $taskItem['id'],
                    'step_category_id' => $taskItem['step_category_id'],
                    'json' => json_decode($taskItem['json'], true)
                ];
            }
        }
        $upEntityStepCategoryTaskMap = array_column($upEntityStepCategoryTaskList, null, 'step_category_id');
        $taskStepCategoryFilter[0]['_logic'] = 'or';
        $taskStepCategoryFilter[] = [
            'step_type' => 'step',
            'entity_id' => ['IN', $entityIds]
        ];
        // 获取每个工序下的最后一条工序任务
        $lastStepCategoryTaskList = model(TaskModel::class)
            ->where($taskStepCategoryFilter)
            ->field('max(id) as id,entity_id,step_category_id,plan_end_time,end_time,json')
            ->group('entity_id,step_category_id')
            ->select();
        $lastStepCategoryTaskMap = array_column($lastStepCategoryTaskList, null, 'id');

        // 检查当前修改计划时间的是否是最后一道工序任务
        if (!array_key_exists($taskData['id'], $lastStepCategoryTaskMap)) {
            return;
        }
        $currentStepCategoryTask = $upEntityStepCategoryTaskMap[$taskData['step_category_id']];
        $currentStepCategoryTaskIsOverdue = $currentStepCategoryTask['json']['task_is_overdue'] ?? '';

        if ($currentStepCategoryTaskIsOverdue != $currentTaskIsOverdue) {
            model(TaskModel::class)->execute("UPDATE task SET json = JSON_SET(IFNULL(json, '{}'), concat('$.task_is_overdue'), '{$currentTaskIsOverdue}') where id = {$upEntityStepCategoryTaskMap[$lastStepCategoryTaskMap[$taskData['id']]['step_category_id']]['id']}");
        }

        // 检查其他工序分类下的最后一道工序任务是否存在未完成逾期
        $upStreamEntityAbnormal = $upStreamEntityData['is_abnormal'];
        $hasOverdueNotDoneTask = false;
        foreach ($lastStepCategoryTaskList as $item) {
            $item['json'] = json_decode($item['json'], true);
            // 逾期未完成
            if ($item['json']['task_status'] != $finalStatus['id'] && $item['plan_end_time'] != 0 && $item['plan_end_time'] < strtotime(date('Y-m-d H:i:s'))) {
                $hasOverdueNotDoneTask = true;
                break;
            }
        }

        $isAbnormalFieldName = '$.' . module_by_id($upStreamEntityData['module_id'])['code'] . '_is_abnormal';
        // 已经有逾期任务 如果实体不为异常 修改为异常
        if ($hasOverdueNotDoneTask && $upStreamEntityAbnormal != 'yes') {
            model(EntityModel::class)->execute("UPDATE entity  SET json = JSON_SET(IFNULL(json, '{}'), '{$isAbnormalFieldName}', 'yes') where  id = {$upStreamEntityData['id']}");
            return;
        }


        $hasRepairTask = false;
        // 检查所有工序任务是否存在返修
        foreach ($taskList as $taskItem) {
            $taskItem['json'] = json_decode($taskItem['json'], true);
            if ($taskItem['step_type'] == 'step' && $taskItem['json']['task_status'] == $remakeStatus['id']) {
                $hasRepairTask = true;
                break;
            }
        }

        if ($hasRepairTask && $upStreamEntityAbnormal != 'yes') {
            model(EntityModel::class)->execute("UPDATE entity  SET json = JSON_SET(IFNULL(json, '{}'), '{$isAbnormalFieldName}', 'yes') where  id = {$upStreamEntityData['id']}");
            return;
        }

        if (!$hasOverdueNotDoneTask && !$hasRepairTask && $upStreamEntityAbnormal == 'yes') {
            model(EntityModel::class)->execute("UPDATE entity  SET json = JSON_SET(IFNULL(json, '{}'), '{$isAbnormalFieldName}', 'no') where  id = {$upStreamEntityData['id']}");
            return;
        }
    }
}
